package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.constants.message.PublishArticleConstants;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFeign;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @作者 itcast
 * @创建日期 2021/9/25 10:52
 **/
@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {
    @Autowired
    WmNewsMapper wmNewsMapper;

    @Value("${file.oss.web-site}")
    String webSite;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Transactional
    @Override
    public void autoScanWmNews(Integer id) {
        log.info("自动审核方法触发---  审核newsId : {}",id);
        // 1. 根据id查询wmNews数据
        if(id == null){
            log.error("自动审核失败   原因: 文章id为null");
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"id为空");
        }
        WmNews wmNews = wmNewsMapper.selectById(id);
        // 2. 判断存在  判断状态
        if (wmNews == null) {
            log.error("自动审核失败   原因: 对应的文章信息不存在");
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"对应的文章信息不存在");
        }
        // 3. 判断状态是否为1  (消息幂等性)
        if(!WemediaConstants.WM_NEWS_SUMMIT_STATUS.equals(wmNews.getStatus())){
            log.info("文章状态不为1   无需审核");
            return;
        }
        // 3.1 抽取文章所有文本内容  及  所有图片
        //  Map <String, Object>   {  content :  文本内容  ,  images :  List<String>  图片路径集合}
        Map<String,Object> contentAndImages =  handleTextAndImages(wmNews);
        // 3.2 DFA敏感词文本审核    不通过： 状态 2   通过下一步
        boolean scanSensitive = handleSensitive((String)contentAndImages.get("content"),wmNews);
        if(!scanSensitive) return;
        // 3.3 阿里云文本审核      不通过:  状态2   不确定: 状态3  通过下一步
        boolean isTextScan = handleTextScan((String)contentAndImages.get("content"),wmNews);
        if(!isTextScan) return;
        // 3.4 阿里云图片审核       不通过:  状态2   不确定: 状态3  通过下一步
        List<String> images = (List<String>) contentAndImages.get("images");
        if (CollectionUtils.isNotEmpty(images)) {
            boolean isImageScan = handleImageScan(images,wmNews);
            if(!isImageScan) return;
        }
        // 4.  将文章的状态改为 8
        updateWmNews(wmNews,(short) 8 ,"审核通过");
        // 5. TODO  文章发布功能发送消息  通知发布文章
        // 发布时间
        long publishTime = wmNews.getPublishTime().getTime();
        // 当前时间
        long nowTime = new Date().getTime();
        long remainTime = publishTime - nowTime;
        if(remainTime <= 0){
            // 立即发布
            rabbitTemplate.convertAndSend(PublishArticleConstants.PUBLISH_ARTICLE_EXCHANGE
                    ,PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY
                    ,wmNews.getId()
            );
            log.info("立即发布文章通知成功发送，文章id : {}",wmNews.getId());
        }else {
            // 延时发布
            rabbitTemplate.convertAndSend(PublishArticleConstants.PUBLISH_ARTICLE_EXCHANGE
                    , PublishArticleConstants.PUBLISH_ARTICLE_DEAD_ROUTE_KEY
                    , wmNews.getId()
                    , (message)-> {
                        message.getMessageProperties().setExpiration(String.valueOf(remainTime));
                        return message;
                    }
            );
            log.info("延时发布文章通知成功发送，文章id : {} , 延时时间: {}毫秒",wmNews.getId(),remainTime);
        }
    }


    @Autowired
    GreenImageScan greenImageScan;
    /**
     * 审核文章图片是否违规
     * @param images
     * @param wmNews
     * @return
     */
    private boolean handleImageScan(List<String> images, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenImageScan.imageUrlScan(images);
            String suggestion = (String)map.get("suggestion");
            // PASS  REVIEW  BLOCK
            switch (suggestion){
                case "review":
                    updateWmNews(wmNews,(short)3,"图片中有不确定因素，转为人工审核");
                    flag = false;
                    break;
                case "block":
                    updateWmNews(wmNews,(short)2,"图片中有违规内容，审核不通过");
                    flag = false;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            updateWmNews(wmNews,(short)3,"阿里云调用失败，转为人工审核");
            log.error("阿里云调用失败，转为人工审核  , 异常信息: {}",e.getMessage());
        }
        return flag;
    }


    @Autowired
    GreenTextScan greenTextScan;

    /**
     * 使用阿里云内容安全  审核文本是否违规
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenTextScan.greenTextScan(content);
            String suggestion = (String)map.get("suggestion");
            // PASS  REVIEW  BLOCK
            switch (suggestion){
                case "review":
                    updateWmNews(wmNews,(short)3,"内容中有不确定因素，转为人工审核");
                    flag = false;
                    break;
                case "block":
                    updateWmNews(wmNews,(short)2,"内容中有违规词汇，审核不通过");
                    flag = false;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            updateWmNews(wmNews,(short)3,"阿里云调用失败，转为人工审核");
            log.error("阿里云调用失败，转为人工审核  , 异常信息: {}",e.getMessage());
        }
        return flag;
    }


    private void updateWmNews(WmNews wmNews, Short status, String reason){
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }


    @Autowired
    AdminFeign adminFeign;

    /**
     * 检查 文本内容中是否包含敏感词
     * @param content  待检测内容
     * @param wmNews   文章
     * @return  true: 审核通过  false: 失败
     */
    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = true;
        ResponseResult<List<String>> sensitivesResult = adminFeign.sensitives();
        if (sensitivesResult.getCode().intValue()!=0) {
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR,"远程查询敏感词失败");
        }
        // 得到敏感词列表
        List<String> data = sensitivesResult.getData();
        // 转化为DFA数据模型
        SensitiveWordUtil.initMap(data);
        // 检测敏感词
        Map<String, Integer> senstiveMap = SensitiveWordUtil.matchWords(content);
        if(senstiveMap!=null && senstiveMap.size() > 0){
            // 包含敏感词
            updateWmNews(wmNews,(short)2,"包含敏感词:"+senstiveMap);
            flag = false;
            log.info("内容审核未通过   文章id:{}      未通过原因: 包含敏感词{}",wmNews.getId(),senstiveMap);
        }
        return flag;
    }

    /**
     * 抽取  文章中所有  文本  及  图片
     * @param wmNews
     * @return  map {   content :       images:  }
     */
    private Map<String,Object> handleTextAndImages(WmNews wmNews) {
        // content : [ {"type":"text","value":"文本"}, {“type”:image,"value":"url"}  ]
        String contentJson = wmNews.getContent();
        Map result = new HashMap();

        List<Map> contentMapList = JSONArray.parseArray(contentJson, Map.class);
        // 1. 拼接文本内容  "我的家乡好美"      "国家强"  为了避免美国是敏感词  加一个分隔符 "我的家乡好美_hmtt_国家强"
        String content = contentMapList.stream()
                .filter(map -> "text".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.joining("_hmtt_"));
        content += "_hmtt_" + wmNews.getTitle();   // String  final    final char[]    +=   StringBuffer  StringBuilder
        // 抽取了 文本内容
        result.put("content",content);
        // 2. 抽取图片内容

        // 2.1  文章内容中涉及的图片
        List<String> imageList = contentMapList.stream()
                .filter(map -> "image".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.toList());
        // 2.2  文章封面中涉及的图片
        String coverStr = wmNews.getImages();
        if (StringUtils.isNotBlank(coverStr)) { //  封面url,封面url  封面不带前缀访问路径  需要拼接
            List<String> coverList = Arrays.stream(coverStr.split(","))
                    .map(url -> webSite + url)
                    .collect(Collectors.toList());
            imageList.addAll(coverList);
        }
        // 2.3  去重
        imageList = imageList.stream().distinct().collect(Collectors.toList());
        result.put("images",imageList);
        return result;
    }
}
